package library.net.retrofit.callback;

import android.os.Handler;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import library.net.retrofit.exception.RxExceptionHandler;
import okhttp3.ResponseBody;
import retrofit2.Callback;

/**
 * @author Created by qiang.hou on 2017/12/18.
 * @version 1.0
 */
public abstract class RxAbsCallback<T> implements Callback<ResponseBody>, IRxCallback<T> {
    /**
     * on start
     *
     * @param tag tag
     */
    public void onStart(Object tag) {
    }

    /**
     * on pause
     *
     * @param tag tag
     * @param t   result(response)
     */
    public void onPause(Object tag, T t) {
    }

    /**
     * on progress(for download)
     *
     * @param tag           tag
     * @param speed         download speed
     * @param currentLength already download length
     * @param totalLength   total size of download file
     */
    public void onProgress(Object tag, long speed, long currentLength, long totalLength) {
    }

    /**
     * on success
     *
     * @param tag tag
     * @param t   result(response)
     */
    public void onSuccess(Object tag, T t) {
    }

    /**
     * on success
     *
     * @param tag    tag
     * @param t      result(response)
     * @param method http method
     */
    public void onSuccess(Object tag, T t, String method) {
    }

    /**
     * on success(for download)
     *
     * @param tag      tag
     * @param path     local path
     * @param name     local file name
     * @param fileSize size of download file
     */
    public void onSuccess(Object tag, String path, String name, long fileSize) {
    }

    /**
     * on complete
     *
     * @param tag tag
     */
    public void onCompleted(Object tag) {
    }

    /**
     * on complete
     *
     * @param tag tag
     * @param t   result(response)
     */
    public void onCompleted(Object tag, T t) {
    }

    /**
     * on error
     *
     * @param tag tag
     * @param e   throwable
     */
    public void onError(Object tag, Throwable e) {
    }

    /**
     * on cancel
     *
     * @param tag tag
     * @param t   result(response)
     */
    public void onCancel(Object tag, T t) {
    }

    /**
     * release some resources
     */
    public void onRelease() {
    }

    /**
     * 子类可以复写 默认不做后端数据校验 子类指定规则
     * if you parse response data in transform, you should make this method return true.
     *
     * @param tag  tag
     * @param body ResponseBody
     * @return boolean
     */
    protected boolean checkResponseOk(Object tag, ResponseBody body) {
        return true;
    }

    /**
     * Thread Pool Thread
     *
     * @param response ResponseBody
     */
    private T onHandleResponse(ResponseBody response) throws Exception {
        return transform(response, ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }

    protected abstract T transform(ResponseBody response, Type type) throws Exception;

    @Override
    public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
        if (call.isCanceled()) {
            onCancel(call.request().tag(), null);
        }
        if (response.isSuccessful() && checkResponseOk(call.request().tag(), response.body())) {
            try {
                onSuccess(call.request().tag(), onHandleResponse(response.body()), call.request().method());
            } catch (Exception e) {
                e.printStackTrace();
                onError(call.request().tag(), RxExceptionHandler.handleException(e));
            }
        }
    }

    @Override
    public void onFailure(retrofit2.Call<ResponseBody> call, Throwable e) {
        onError(call.request().tag(), RxExceptionHandler.handleException(e));
    }
}
